flowchart LR
A[Ordinateur] -->|1. Où est google.com?| B[DNS]
B -->|2. IP: 142.250.217.110| A
A -->|3. Connexion| C[Google]
Introduction aux mégadonnées en sciences sociales
Université de Montréal
ARPANET en 1973
Principe fondamental
Exemples
Carte physique de l’internet
❯ tcptraceroute umontreal.ca
Selected device wlp3s0, address 192.168.2.71, port 45431 for outgoing packets
Tracing the path to umontreal.ca (132.204.8.144) on TCP port 80 (http), 30 hops max
1 192.168.2.1 5.618 ms 1.743 ms 2.499 ms
2 10.11.16.41 3.860 ms 4.041 ms 3.737 ms
3 * **
4 64.230.36.102 6.344 ms 7.423 ms 9.020 ms
5 64.230.91.65 5.214 ms 5.570 ms 6.500 ms
6 192.77.55.233 6.890 ms 6.169 ms 5.786 ms
7 imtrl-rq-ic-dmtrl-rq.risq.net (192.77.55.246) 5.837 ms 9.565 ms 7.724 ms
8 umontreal2-contenu-dmtrl-um.risq.net (132.202.51.145) 32.002 ms 6.428 ms 7.800 ms
9 * **
10 umontreal2-contenu-membre.risq.net (206.167.253.66) 33.855 ms 8.017 ms 6.263 ms
11 * **
12 * **
13 varnish.ti.umontreal.ca (132.204.8.144) [open] 10.542 ms 9.826 ms 13.408 msVotre ordinateur (192.168.2.71)
Point de départ à Québec
Routeur résidentiel (192.168.2.1) Votre passerelle vers Internet
Routeur Bell Fibe (10.11.16.41)
Entrée dans l’infrastructure de Bell Canada
Dorsale Bell Canada (64.230.36.102) Infrastructure principale de Bell - câbles à haute capacité (jusqu’à 100 Tbps sur certaines lignes)
Point régional Bell (64.230.91.65) Transfert vers Montréal - connexion interurbaine
RISQ - Point d’entrée (192.77.55.233) Entrée dans le Réseau d’Informations Scientifiques du Québec
RISQ - Interconnexion Montréal (192.77.55.246) Routage interne du réseau académique québécois
RISQ - Passerelle UdeM (132.202.51.145) La porte d’entrée spécifique à l’Université de Montréal
UdeM - Réseau membre (206.167.253.66) Transfert au réseau interne de l’UdeM
Serveur Varnish UdeM (132.204.8.144) Destination finale: serveur de cache accélérant la livraison du site
Tapez dans votre navigateur: http://142.250.217.110
flowchart LR
A[Ordinateur] -->|1. Où est google.com?| B[DNS]
B -->|2. IP: 142.250.217.110| A
A -->|3. Connexion| C[Google]
Moissonnage / Aspiration / Grattage de données sur le Web
➡️
Accès exhaustif à d’immense corpus de documents médias, accords internationaux, discours et procédures parlementaires, rapports annuels d’entreprises, jurisprudences, etc.
La trace digitale des réseaux sociaux permet l’étude de nombreux phénomènes sociaux
Question de recherche
Est-ce que se faire élire jeune est un avantage pour rester premier ministre longtemps?
Pour répondre, nous devons recueillir:
Répéter pour CHAQUE premier ministre…
…et encore 18 autres premiers ministres! 😓
Trouver les données voulues
# URL of the page to scrape
url <- "https://lop.parl.ca/sites/ParlInfo/default/en_CA/People/primeMinisters"
# Read the webpage
page <- xml2::read_html(url)
elem <- rvest::html_table(page, "table.dx-datagrid-table")➡️ Retour sur le site web!
Permet de voir que le tableau n’est pas visible dans la page
Astuce
Dans notre cas, nous avons découvert une API du Parlement du Canada!
# Exemple de notre URL d'API pour les premiers ministres
api_url <- "https://lop.parl.ca/ParlinfoWebAPI/Person/SearchAndRefine?&refiners=5-1,&projectionId=5&callback=jQuery3600941572194102592_1741730322226&_=1741730322227"Note
Les API sont souvent masquées mais peuvent être découvertes en inspectant les requêtes réseau!
https://www.parlement.ca/premiers-ministres?periode=1950-2020&lang=fr
Protocole https:// Communication sécurisée
Domaine www.parlement.ca Localisation du site
Chemin /premiers-ministres Ressource spécifique
Paramètres ?periode=1950-2020&lang=fr Filtres et options
Comprendre ces composants permet d’identifier quelles parties de l’URL modifier pour accéder aux données souhaitées lors du web scraping
Pour le HTML : library(rvest) et library(xml2)
Pour le JSON (notre cas) :
json$premiers_ministres$details$parti$nom
{
"premiers_ministres": [
{
"nom": "Justin Trudeau",
"details": {
"naissance": "1971-12-25",
"parti": {
"nom": "Libéral",
"couleur": "rouge"
}
},
"en_fonction": true
},
{
"nom": "Stephen Harper",
"details": {
"naissance": "1959-04-30",
"parti": {
"nom": "Conservateur",
"couleur": "bleu"
}
},
"en_fonction": false
}
],
"derniere_mise_a_jour": "2023-09-15"
}# Création d'un dataframe avec les informations principales
df_pm <- data.frame(
name = paste(pm_data$UsedFirstName, pm_data$LastName),
yob = pm_data$DateOfBirth, # Date de naissance
Party = pm_data$PartyEn, # Parti politique
occupation = pm_data$ProfessionsEn, # Profession
province = pm_data$ProvinceOfBirthEn, # Province de naissance
stringsAsFactors = FALSE
)start_date <- c()
end_date <- c()
# Parcourir chaque premier ministre pour extraire les dates de mandat
for (i in 1:nrow(pm_data)) {
# Récupérer tous les rôles politiques de la personne
roles <- pm_data$Roles[[i]]
# Parcourir chaque rôle pour trouver "Premier ministre"
for (j in 1:nrow(roles)) {
# Vérifier si le titre inclut "Premier ministre"
if ("Premier ministre" %in% roles$NameFr) {
# Enregistrer les dates de début et fin
start_date[i] <- roles$StartDate[j]
end_date[i] <- roles$EndDate[j]
}
}
}# Conversion des dates en format Date de R
df_pm$start_date <- as.Date(substr(start_date, 1, 10))
df_pm$end_date <- as.Date(substr(end_date, 1, 10))
df_pm$yob <- as.Date(substr(df_pm$yob, 1, 10))
# Calcul de variables d'intérêt
df_pm$duration <- as.numeric(difftime(df_pm$end_date,
df_pm$start_date,
units = "days"))/365.25
df_pm$age_at_start <- as.numeric(difftime(df_pm$start_date,
df_pm$yob,
units = "days"))/365.25# Régression linéaire: durée ~ âge au début
model <- lm(duration ~ age_at_start, data = df_pm)
summary(model)r$> summary(m)
Call:
lm(formula = duration ~ age_at_start, data = df_pm)
Residuals:
Min 1Q Median 3Q Max
-5.6546 -3.6723 -0.0936 3.4233 9.6509
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 8.40307 5.52676 1.520 0.143
age_at_start -0.05162 0.09679 -0.533 0.599
Residual standard error: 4.515 on 21 degrees of freedom
Multiple R-squared: 0.01336, Adjusted R-squared: -0.03362
F-statistic: 0.2845 on 1 and 21 DF, p-value: 0.5994Important
Est-ce que les plus jeunes premiers ministres ont tendance à rester plus longtemps en poste? NON!
rvest)httr, jsonlite)Pour chaque méthode de scraping, nous verrons:
#myTable# Chargement des packages nécessaires
library(rvest) # Pour le scraping HTML
library(dplyr) # Pour la manipulation de données
library(stringr) # Pour la manipulation de texte
# 1. URL de la page à scraper
url <- "https://338canada.com/districts.htm"
# 2. Lecture de la page web
html_content <- read_html(url)
# 3. Extraction du tableau HTML
table_data <- html_content %>%
html_node("#myTable") %>% # Sélectionne le tableau par son ID CSS
html_table(fill = TRUE) # Convertit en dataframe# 4. Extraction des informations utiles
# 4.1 Extraire l'ID de circonscription (format 12345)
table_data$riding_id <- str_extract(table_data$electoral_district, "\\d{5}")
# 4.2 Extraire le nom propre de la circonscription
table_data$district_name <- str_replace_all(table_data$electoral_district, "\\d{5} ", "")
# 4.3 Extraire le parti projeté gagnant (LPC, CPC, NDP, BQ, GPC)
table_data$projected_party <- str_extract(table_data$latest_projection, "(LPC|CPC|NDP|BQ|GPC)")
# 4.4 Extraire le statut de la projection (safe, likely, leaning)
table_data$projection_status <- str_replace_all(table_data$latest_projection, "(LPC|CPC|NDP|BQ|GPC) ", "")
# 5. Création d'un dataframe propre et sauvegarde
clean_data <- table_data %>%
select(riding_id, district_name, projected_party, projection_status) %>%
filter(!is.na(riding_id)) # Supprime les lignes sans ID (entêtes)
# 6. Ajout de la date du scraping et sauvegarde
clean_data$scrape_date <- Sys.Date()
saveRDS(clean_data, "data/lake/can338/338_canada_projection.rds")#myTabletable:nth-child(2).data-tablediv.content tablefill = TRUE pour les tableaux irréguliersSimplissime: Télécharger directement le fichier Excel et le sauvegarder!
# Chargement du package pour Excel
library(readxl)
# 1. Création d'un fichier temporaire avec extension .xlsx
temp_file <- tempfile(fileext = ".xlsx")
# 2. Téléchargement du fichier
download.file(
"https://www.poliwave.com/Canada/Federal/Data/CAtable.xlsx",
temp_file,
mode = "wb" # Mode binaire important pour Excel
)
# 3. Lecture du fichier Excel
poliwave_ridings <- readxl::read_xlsx(temp_file)
# 4. Sauvegarde en format RDS
saveRDS(
poliwave_ridings,
"data/lake/poliwave/poliwave_table.rds"
)| Package | Fonction | Description |
|---|---|---|
httr |
GET() |
Effectue une requête HTTP GET à une URL |
httr |
content() |
Extrait le contenu d’une réponse HTTP |
jsonlite |
fromJSON() |
Parse une chaîne JSON en objet R |
# Chargement des packages
library(dplyr) # Pour la manipulation de données
library(httr) # Pour les requêtes HTTP
library(jsonlite) # Pour le parsing JSON
# 1. Configuration de base
# URL de l'API pour les projections électorales
api <- "https://thesignal-api.voxpoplabs.com/api/en/canada2025/riding_projections"
# 4. Exécution de la requête API
response <- httr::GET(api){
"ridings": [
{
"riding_name": "Beauce",
"region": "QC",
"confidence": "Likely",
"prediction": "CON",
"date_updated": "2023-11-15"
},
{
"riding_name": "Toronto Centre",
"region": "ON",
"confidence": "Safe",
"prediction": "LIB",
"date_updated": "2023-11-15"
},
{
"riding_name": "Vancouver Centre",
"region": "BC",
"confidence": "Likely",
"prediction": "LIB",
"date_updated": "2023-11-15"
}
],
"meta": {
"last_updated": "2023-11-15T12:00:00Z",
"version": "1.0"
}
}Packages: rvest, xml2
Packages: utils, readxl, readr
Packages: httr, jsonlite
User-agent: *
Disallow: /private/
Disallow: /admin/
Allow: /public/
User-agent: Googlebot
Allow: /
Un guide pour les robots, mais pas une barrière de sécurité
Éthique du web scraping
La règle générale: toujours vérifier avant de scraper!
# Installer le package si nécessaire
# install.packages("robotstxt")
library(robotstxt)
# Vérifier si le scraping est autorisé
paths_allowed("https://lop.parl.ca/sites/ParlInfo/default/en_CA/People/primeMinisters")
#> [1] TRUE
paths_allowed("https://lop.parl.ca/ParlinfoWebAPI/Person/SearchAndRefine?&refiners=5-1,&projectionId=5&callback=jQuery360032980273762339296_1741814357460&_=1741814357461")
#> [1] TRUE
# Examiner le fichier robots.txt complet
robotstxt::get_robotstxt("https://lop.parl.ca")Le package
robotstxtfacilite la vérification avant le web scraping
r$> robotstxt::get_robotstxt("https://lop.parl.ca")
[robots.txt]
--------------------------------------
User-agent: *
Disallow: /staticfiles/PublicWebsite/Home/About/CoporateDocuments/PDFExc
ludedInRobotsTXT
Disallow: /content/lop/Quorum
Disallow: /Content/LOP/Quorum
Disallow: /Content/LOP/quorum
Disallow: /Content/lop/quorum
Disallow: /content/lop/quorum
Disallow: /content/LOP/Quorum
Disallow: /sites/PublicWebsite/default/en_CA/NotFound
Disallow: /sites/PublicWebsite/default/fr_CA/NotFound
Disallow: /sites/ParlInfo/default/en_CA/SiteInformation/parlinfoMoved
Disallow: /sites/ParlInfo/default/fr_CA/InformationSite/parlinfoDemenage
Allow: /sites/ParlInfo/default/en_CA/People/Profile?*
Disallow: /sites/ParlInfo/default/en_CA/People/Profile
Allow: /sites/ParlInfo/default/fr_CA/Personnes/Profil?*
Allow: /sites/ParlInfo/default/fr_CA/Personnes/Profile?*
Disallow: /sites/ParlInfo/default/fr_CA/Personnes/Profil
Disallow: /sites/ParlInfo/default/fr_CA/Personnes/Profile
Allow: /sites/ParlInfo/default/en_CA/Federal/areasResponsibility/profile
?*
Disallow: /sites/ParlInfo/default/en_CA/Federal/areasResponsibility/prof
ile
Allow: /sites/ParlInfo/default/fr_CA/Federal/domainesResponsabilites/pro
fil?*
Disallow: /sites/ParlInfo/default/fr_CA/Federal/domainesResponsabilites/
profil
Allow: /sites/ParlInfo/default/en_CA/Parties/Profile?*
Disallow: /sites/ParlInfo/default/en_CA/Parties/Profile
Allow: /sites/ParlInfo/default/fr_CA/Partis/Profil?*
Disallow: /sites/ParlInfo/default/fr_CA/Partis/Profil
Allow: /sites/ParlInfo/default/en_CA/ElectionsRidings/Ridings/Profile?*
Disallow: /sites/ParlInfo/default/en_CA/ElectionsRidings/Ridings/Profile
Allow: /sites/ParlInfo/default/fr_CA/ElectionsCirconscriptions/Circonscr
iptions/Profil?*
Disallow: /sites/ParlInfo/default/fr_CA/ElectionsCirconscriptions/Circon
scriptions/Profil
Allow: /sites/ParlInfo/default/en_CA/ElectionsRidings/Elections/Profile?
*
Disallow: /sites/ParlInfo/default/en_CA/ElectionsRidings/Elections/Profi
le
Allow: /sites/ParlInfo/default/fr_CA/ElectionsCirconscriptions/Elections
/Profil?*
Disallow: /sites/ParlInfo/default/fr_CA/ElectionsCirconscriptions/Electi
ons/Profil
Disallow: /sites/PublicWebsite/default/fr_CA/Staging
Disallow: /sites/PublicWebsite/default/en_CA/Staging
Disallow: /sites/PublicWebsite/default/fr_CA/merc
Disallow: /sites/PublicWebsite/default/en_CA/merc
Sitemap: https://bdp.parl.ca/rss/public/fr/sitemapxml
Sitemap: https://lop.parl.ca/rss/public/en/sitemapxmlUser-agent: * - S’applique à tous les robotsUser-agent: Googlebot - Spécifique à GoogleDisallow: /dossier/ - Interdit l’accèsAllow: /dossier/ - Autorise explicitement l’accèsCrawl-delay: 10 - Attendre 10 secondes entre requêtesToujours associer la vérification de robots.txt à d’autres bonnes pratiques de scraping (délais, user-agent explicite, etc.)
Astuce
Le package polite intègre la vérification de robots.txt et d’autres bonnes pratiques comme les délais entre requêtes.
RSelenium: Pour sites dynamiques (JavaScript)
Comment approcher le problème?
1. Naviguer
Identifier sources et structure des pages
2. Aspirer
Télécharger le contenu
3. Extraire
Isoler les données pertinentes
4. Nettoyer
Structurer pour l’analyse